#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：idi_mes 
@File    ：wip_check_out.py
@IDE     ：PyCharm 
@Date    ：9/26/24 2:50 PM 
"""

from typing import Dict, List, Union, Tuple

from mg_app_framework import MesCode

from common.basic_mongo import get_retrospect_collection, get_container_status_collection, get_rule_code_collection
from common.constant import RetrospectType
from prod_ctrl_service.tool.tool import check_unqualified_record_027


async def check_wip_check_out(params: Dict[str, Union[str, List[str]]]) -> Dict[str, str]:
    """
    上位机上传电芯码，MES校验电芯码的状态是否允许组盘（只做出站是否允许组盘校验、不做进站和出站操作）
    :param params:{
               "call_id":"JQ00386",  #接口调用方认证ID, string
               "trace_id":"8941d16b-0581-4e68-8940-a651afff4282",  #接口调用ID, string
               "upperpc_code": "UP011",    #上位机编码, string
               "user_code":"Y001",  #员工编码, string
               "equip_code":"ZP001",  # 设备编码, string
               "process_code":"2050",   # 工序编码, string, 必输
               "cell_list":["WW202408140001","WW202408140002"]   # 电芯码列表,数组,Y
            }
    :return:
    """
    process_code = params.get("process_code")
    cell_list = params.get("cell_list")
    if process_code == "C220":
        cell_list = await transfor_cell_sn(cell_list)
    error_msg = ""
    # 校验入参的电芯码最新追溯数据是不是本工序出站;
    # 校验入参的电芯码本工序出站数据是否是NG品;
    no_exists_qr_code, process_code_no_map, check_no_qualify_result = await get_last_retrospect(
        qr_code_list=cell_list, process_code=process_code
    )
    if no_exists_qr_code:
        error_msg += f"下列电芯码不存在追溯数据:{no_exists_qr_code};"
    if process_code_no_map:
        error_msg += f"下列电芯码最新的追溯数据不是本工序出站:{process_code_no_map};"
    if check_no_qualify_result:
        error_msg += f"下列电芯码本工序出站数据不合格:{check_no_qualify_result};"
    # 校验入参的电芯码是否已经绑定了其它托盘码
    binding_check_msg = await check_if_cell_sn_bind(cell_sn_list=cell_list)
    if binding_check_msg:
        error_msg += binding_check_msg
    # 校验电芯码是否存在不符合要求的不合格品记录
    unqualified_check_msg = await check_unqualified_record_027(cell_list)
    if unqualified_check_msg:
        error_msg += unqualified_check_msg
    # todo,marking校验
    if error_msg:
        result = {
            "code": MesCode.fail,  # 接口应答状态代码, success：成功; fail：失败, string
            "data": {},  # 接口返回结果描述, json数组, 本接口不需要返回数据，返回null
            "info": error_msg,  # 接口返回信息描述, 如果为fail, 则为fail的异常描述信息, string
        }
    else:
        result = {
            "code": MesCode.success,  # 接口应答状态代码, success：成功; fail：失败, string
            "data": {},  # 接口返回结果描述, json数组, 本接口不需要返回数据，返回null
            "info": "ok",  # 接口返回信息描述, 如果为fail, 则为fail的异常描述信息, string
        }
    return result


async def get_last_retrospect(qr_code_list: list, process_code: str) -> Tuple[List, List, List]:
    """
    获取入参中电芯码在追溯表中前一道工序上的产出信息
    :param process_code:
    :param qr_code_list:
    :return:
    """
    pipeline = [
        {
            "$match": {
                "qr_code": {"$in": qr_code_list},
                "op_type": RetrospectType.PRODUCT_OUT,
                "is_delete": False,
            }
        },
        {"$sort": {"op_time": -1}},
        {"$group": {"_id": "$qr_code", "latestDocument": {"$first": "$$ROOT"}}},
    ]
    collection = get_retrospect_collection()
    qr_code_document_map = {}
    no_exists_qr_code = []  #
    process_code_no_map = []  # 存放最新追溯产出数据不是本工序的码值
    check_no_qualify_result = []  # 存放在前道工序有产出追溯数据，但是产出结果不合格的码值
    async for rec in collection.aggregate(pipeline):
        qr_code = rec["_id"]
        document = rec["latestDocument"]
        qr_code_document_map.update({qr_code: document})
    for cell_sn in qr_code_list:
        if cell_sn not in qr_code_document_map:
            no_exists_qr_code.append(cell_sn)
        else:
            document = qr_code_document_map[cell_sn]
            if document.get("procedure_code") != process_code:
                process_code_no_map.append(cell_sn)
            elif document.get("check_result") == "不合格":
                check_no_qualify_result.append(cell_sn)

    return no_exists_qr_code, process_code_no_map, check_no_qualify_result


async def check_if_cell_sn_bind(cell_sn_list: list) -> str:
    """
    校验入参的电芯码是否已经绑定了其它托盘码
    :param cell_sn_list:
    :return:
    """
    error_msg = ""
    collection = get_container_status_collection()
    query_filter = {
        "product_list.mark": {"$in": cell_sn_list}
    }
    async for rec in collection.find(query_filter):
        container_mark = rec["container_mark"]
        product_list = rec["product_list"]
        for cell_unit in product_list:
            mark = cell_unit.get("mark")
            if mark in cell_unit:
                error_msg += f"电芯码{mark}已经绑定托盘码:{container_mark};"
    return error_msg


async def transfor_cell_sn(cell_list: list):
    """

    :param cell_list:
    :return:
    """
    check_code_map = {item: item for item in cell_list}
    collection = get_rule_code_collection()
    pipeline = [
        {'$match': {"wip_type": 2, "bind_code": {"$in": cell_list}}},
        {"$sort": {"create_time": -1}},
        {"$group": {"_id": "$bind_code", "document": {"$first": "$$ROOT"}}}
    ]
    async for rec in collection.aggregate(pipeline):
        old_cell_sn = rec["_id"]
        document = rec["document"]
        new_cell_sn = document["code"]
        if old_cell_sn in check_code_map:
            check_code_map.update({
                old_cell_sn: new_cell_sn
            })
    new_cell_list = list(check_code_map.values())
    return new_cell_list
